package com.gitee.xmhzzz.component.tcp.server.context;

import com.gitee.xmhzzz.component.tcp.server.config.NettyServerProperties;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.*;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.util.internal.PlatformDependent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * @ClassName TCPNettyServerContext
 * @Description
 * @Author wzq
 * @Date 2024/3/5 13:49
 * @Version 1.0
 */
public class TCPNettyServerContext implements NettyServerContext{

    private static final Logger log = LoggerFactory.getLogger(TCPNettyServerContext.class);

    private static final int DEFAULT_WORKERS=64;

    private ServerBootstrap bootstrap;

    private NettyServerProperties properties;

    public TCPNettyServerContext(NettyServerProperties properties) {
        this.properties = properties;
    }

    @Override
    public TCPNettyServerContext create(ChannelInboundHandlerAdapter adapter) {
        this.bootstrap = new ServerBootstrap();
        EventLoopGroup bossGroup = null;
        EventLoopGroup workerGroup = null;
        Class<? extends ServerChannel> serverChannel = null;
        if (PlatformDependent.isWindows() || PlatformDependent.isOsx()) {
            bossGroup = new NioEventLoopGroup();
            workerGroup = new NioEventLoopGroup(DEFAULT_WORKERS);
            serverChannel = NioServerSocketChannel.class;
        } else {
            bossGroup = new EpollEventLoopGroup();
            workerGroup = new EpollEventLoopGroup(DEFAULT_WORKERS);
            serverChannel = EpollServerSocketChannel.class;
        }
        bootstrap.group(bossGroup,workerGroup).channel(serverChannel)
                .option(ChannelOption.SO_BACKLOG, 2048)
                .option(ChannelOption.TCP_NODELAY, true)
                .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                // 小于默认值
                .option(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(1024 * 24, 1024 * 48))
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    public void initChannel(SocketChannel ch) throws Exception {
                        ChannelPipeline p = ch.pipeline();
                        p.addLast(new LineBasedFrameDecoder(2048));
                        p.addLast(new StringDecoder());
                        p.addLast(adapter);
                    }
                });
        return this;
    }

    @Override
    public void connect() throws Exception {
        if(this.bootstrap == null){

        }
        try {
            // 绑定端口，同步等待成功
            ChannelFuture channelFuture = this.bootstrap.bind(this.getPort()).sync();
            log.info("tcp server port:{}",this.getPort());
            // 等待服务端监听端口关闭
            channelFuture.channel().closeFuture().sync();
        } finally {
            // 优雅退出，释放线程池资源
            EventLoopGroup bossGroup = bootstrap.group();
            EventLoopGroup workerGroup = bootstrap.childGroup();
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    @Override
    public void stop() {

    }

    @Override
    public Integer getPort() {
        return properties.getPort();
    }

    @Override
    public String getAppSecret(String appId) {
        return null;
    }
}
